package com.jackeysun.widget.media

import android.media.AudioAttributes
import android.media.AudioManager
import android.media.MediaPlayer
import android.os.Build
import android.util.Log
import android.media.PlaybackParams


/**
 *   Created by sunxunchao on 2021/12/29.
 *   @link #https://developer.android.google.cn/images/mediaplayer_state_diagram.gif
 */
open class SimplePlayer : IPlayer {

    interface OnPlayerStatusChangeListener {
        fun onStatusChanged(status: Status)
    }

    enum class Status {
        INIT,
        PREPARING,
        PREPARED,
        PLAYING,
        PAUSE,
        STOP,
        ERROR,
        RELEASE,
        COMPLETE
    }

    private val TAG = SimplePlayer::class.java.simpleName

    val mMediaPlayer: MediaPlayer by lazy {
        MediaPlayer()
    }

    var isVideo: Boolean = false
    var isLooping: Boolean = false

    var status: Status = Status.INIT

    private var speed: Float = 1.0f

    var onPlayerStatusChangeListener: OnPlayerStatusChangeListener? = null

    override fun reset() {
        status = Status.INIT
        onPlayerStatusChangeListener?.onStatusChanged(status)
        mMediaPlayer.reset()
    }

    override fun setSource(path: String) {
        try {
            listener()
            status = Status.PREPARING
            onPlayerStatusChangeListener?.onStatusChanged(status)
            mMediaPlayer.apply {
                setAudioAttributes(
                    AudioAttributes.Builder().setContentType(
                        if (isVideo) AudioAttributes.CONTENT_TYPE_MOVIE
                        else AudioAttributes.CONTENT_TYPE_MUSIC
                    ).build()
                )
                setDataSource(path)
                prepareAsync()
            }
        } catch (e: Exception) {
            e.printStackTrace()
            status = Status.ERROR
            onPlayerStatusChangeListener?.onStatusChanged(status)
        }
    }

    private fun listener() {
        mMediaPlayer.apply {
            setOnCompletionListener {
                status = Status.COMPLETE
                onPlayerStatusChangeListener?.onStatusChanged(status)
            }
            setOnErrorListener { mp, what, extra ->
                Log.d(TAG, "init: what : $what  extra : $extra")
                status = Status.ERROR
                onPlayerStatusChangeListener?.onStatusChanged(status)
                true
            }
            setOnPreparedListener {
                status = Status.PREPARED
                onPlayerStatusChangeListener?.onStatusChanged(status)
            }
        }
    }

    override fun start() {
        try {
            status = Status.PLAYING
            onPlayerStatusChangeListener?.onStatusChanged(status)
            mMediaPlayer.isLooping = isLooping
            mMediaPlayer.start()
        } catch (e: Exception) {
            e.printStackTrace()
            status = Status.ERROR
            onPlayerStatusChangeListener?.onStatusChanged(status)
        }
    }

    override fun pause() {
        try {
            mMediaPlayer.pause()
            status = Status.PAUSE
            onPlayerStatusChangeListener?.onStatusChanged(status)
        } catch (e: Exception) {
            e.printStackTrace()
            status = Status.ERROR
            onPlayerStatusChangeListener?.onStatusChanged(status)
        }
    }

    override fun stop() {
        try {
            mMediaPlayer.stop()
            status = Status.STOP
            onPlayerStatusChangeListener?.onStatusChanged(status)
        } catch (e: Exception) {
            e.printStackTrace()
            status = Status.ERROR
            onPlayerStatusChangeListener?.onStatusChanged(status)
        }
    }

    override fun release() {
        try {
            mMediaPlayer.release()
            status = Status.RELEASE
            onPlayerStatusChangeListener?.onStatusChanged(status)
        } catch (e: Exception) {
            e.printStackTrace()
            status = Status.ERROR
            onPlayerStatusChangeListener?.onStatusChanged(status)
        }
    }

    override fun seekTo(msec: Int) {
        try {
            mMediaPlayer.seekTo(msec)
        } catch (e: Exception) {
            e.printStackTrace()
            status = Status.ERROR
            onPlayerStatusChangeListener?.onStatusChanged(status)
        }
    }

    override fun setSpeed(speed: Float): Float {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            try {
                val params: PlaybackParams = mMediaPlayer.playbackParams
                params.speed = speed
                mMediaPlayer.playbackParams = params
                AbsPlayer@ this.speed = speed
                AbsPlayer@ this.speed
            } catch (e: Exception) {
                e.printStackTrace()
                AbsPlayer@ this.speed
            }
        } else {
            AbsPlayer@ this.speed
        }
    }

    override fun setVolume(leftVolume: Float, rightVolume: Float) {
        mMediaPlayer.setVolume(leftVolume, rightVolume)
    }


    override fun getDuration(): Int = try {
        mMediaPlayer.duration
    } catch (e: Exception) {
        e.printStackTrace()
        0
    }

    override fun getCurrentPosition(): Int = try {
        mMediaPlayer.currentPosition
    } catch (e: Exception) {
        e.printStackTrace()
        0
    }

    override fun isPlaying(): Boolean = try {
        mMediaPlayer.isPlaying
    } catch (e: Exception) {
        false
    }

    /**
     * @param durationHint
     * AudioManager.AUDIOFOCUS_LOSS <---> AUDIOFOCUS_GAIN 需要stop播放和释放
     * AudioManager.AUDIOFOCUS_LOSS_TRANSIENT <---> AUDIOFOCUS_GAIN_TRANSIENT 需要pause播放
     * AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK <---> AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK 可以继续播放，只是需要降低音量或音量置为0
     * AudioManager.AUDIOFOCUS_GAIN 恢复播放
     */
    override fun requestAudioFocusSuccess(audioManager: AudioManager, durationHint: Int): Boolean {
        return audioManager.requestAudioFocus(
            audioFocusChangeListener,
            AudioManager.STREAM_MUSIC,
            durationHint,
        ) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED
    }

    override fun abandonAudioFocusSuccess(audioManager: AudioManager): Boolean =
        audioManager.abandonAudioFocus(audioFocusChangeListener) ==
                AudioManager.AUDIOFOCUS_REQUEST_GRANTED

    private val audioFocusChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange ->
        Log.d(TAG, ": $focusChange")
        when (focusChange) {
            AudioManager.AUDIOFOCUS_GAIN -> {
                if (status == Status.PAUSE){
                    start()
                }
            }
            AudioManager.AUDIOFOCUS_LOSS -> {
                if (isPlaying()) {
                    stop()
                }
            }
            AudioManager.AUDIOFOCUS_GAIN_TRANSIENT->{
                if (status == Status.PAUSE) {
                    start()
                }
            }
            AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
                if (isPlaying()) {
                    pause()
                }
            }
            AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
                setVolume(0.1f, 0.1f)
            }
            AudioManager.AUDIOFOCUS_REQUEST_FAILED -> {
                if (isPlaying()) {
                    stop()
                }
            }
        }
    }
}